/**
*  \file kwptptx.c
*
*  \brief KWP2000 CAN Transmission Protocol
*
*  \author Michael J. Hohmann  <michael.hohmann@linde-mh.de>
*
*

@startuml
[*]-->kwptptx_state_idle
kwptptx_state_idle--> kwptptx_state_wait_flow_control
kwptptx_state_idle--> kwptptx_state_idle
kwptptx_state_wait_flow_control--> kwptptx_state_send_consecutive
kwptptx_state_send_consecutive-->kwptptx_state_wait_flow_control
kwptptx_state_send_consecutive-->kwptptx_state_idle
@enduml

*/

/*===============================================[ private includes  ]================================================*/
#include "kwptptx.h"
#include "../assertor/assertor.h"
#include "../pal/pal_mem.h"
#include "../systime/systime.h"
/*===============================================[ private defines   ]================================================*/

/*===============================================[ private datatypes ]================================================*/


/*===============================================[ private variables ]================================================*/

/*===============================================[ private functions ]================================================*/

/*================================================[ inline functions ]================================================*/

/*================================================[ public functions ]================================================*/

RC kwptptx_construct( struct kwptptx_obj *me, kwptptx_transmit_func_t transmit_func )
{	
   ASSERTOR_PRE( NIL != me,"NIL is not allowed as object pointer." );
   pal_memzero( me, sizeof *me );

   me->transmit=transmit_func;

   me->flow_control_timeout = 5000;

   return RC_SUCCESS;
}

BO kwptptx_start_transmission( struct kwptptx_obj *me, struct kwp_msg *p_msg )
{
   /* send single frame */
   if(p_msg->len <=7 )
   {
      U8 data[8]={ p_msg->len, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
      pal_memcpy( &data[1], &p_msg->data[0], p_msg->len );
      me->transmit( data );
      me->p_read_buffer = NIL;/* nothing to do anymore */
      return TRUE; /* done */
   }

   {
      /* send first frame */
      U8 data[8]={ 0x10 | (p_msg->len>>8), p_msg->len & 0xFF, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00 };
      pal_memcpy( &data[2], &p_msg->data[0], 0x06 );
      me->transmit(data);

      me->bytes_to_send = p_msg->len - 6;
      me->p_read_buffer = &p_msg->data[6];
      me->sequence_number=1;
      me->flow_control_timer=systime_get();
      me->expect_flow_control=TRUE;

      return FALSE; /* transmission in progress */
   }
}


BO kwptptx_cyclic_service( struct kwptptx_obj *me )
{
   if( NIL == me->p_read_buffer )
   {
      return TRUE; /* nothing to do */
   }

   if(me->expect_flow_control)
   {
      if( systime_timeout( me->flow_control_timer, me->flow_control_timeout ) )
      {
         me->expect_flow_control=FALSE;
         me->p_read_buffer = NIL;
         return TRUE; /* we are done here */
      }
      else
      {
         return FALSE;
      }
   }

   if( systime_timeout( me->separation_timer, me->separation_time) )
   {
      {
         U16 bytes_in_this_frame = me->bytes_to_send;
         U8 data[8]={ 0x20 | (me->sequence_number & 0x0F) , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

         /* maximum length is 7 bytes */
         if( bytes_in_this_frame > 7)
         {
            bytes_in_this_frame=7;
         }
         pal_memcpy( &data[1], me->p_read_buffer, bytes_in_this_frame );
         me->transmit(data);
         me->bytes_to_send-=bytes_in_this_frame;
         me->p_read_buffer+=bytes_in_this_frame;
      }

      me->separation_timer=systime_get();

      me->sequence_number++;

      if( 0 == me->bytes_to_send) /* is this is the last message */
      {
         me->p_read_buffer=NIL;
         return TRUE;
      }

      if( me->block_count != 0 )
      {
         me->block_count--;
         if( me->block_count == 0 )
         {
            me->expect_flow_control=TRUE; /* wait for flow */
            me->flow_control_timer=systime_get();
         }
      }
   }

   return FALSE;
}

void kwptptx_process_msg( struct kwptptx_obj *me, U8 *data )
{
   if( me->expect_flow_control )
   {
      if(data[0]==0x30)
      {
         me->block_count=data[1];
         me->separation_time=data[2];
         me->expect_flow_control=FALSE;
         me->separation_timer=systime_get();
      }
   }
}

/*===============================================[ private functions ]================================================*/

/***********************************************************************************************************************
*                             Copyright 2020 Linde Material Handling. All rights reserved.                             *
***********************************************************************************************************************/
